﻿//FortsDailyData.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.History.Rts
{
	using System;
	using System.Collections.Generic;
	using System.Globalization;
	using System.Linq;
	using System.Text;
	using System.IO;
	using System.Net;
	using System.Xml.Linq;

	using Ecng.Common;
	using Ecng.Collections;

	using StockSharp.BusinessEntities;
	using StockSharp.Logging;

	/// <summary>
	/// Дневаная информация по инструменту.
	/// </summary>
	public class SecurityDailyData
	{
		/// <summary>
		/// Дата.
		/// </summary>
		public DateTime Date { get; set; }
		
		/// <summary>
		/// Средняя цена.
		/// </summary>
		public decimal AveragePrice { get; set; }
		
		/// <summary>
		/// Расчетная цена.
		/// </summary>
		public decimal CalculatedPrice { get; set; }
		
		/// <summary>
		/// Цена открытия.
		/// </summary>
		public decimal Open { get; set; }
		
		/// <summary>
		/// Максимум дня.
		/// </summary>
		public decimal High { get; set; }
		
		/// <summary>
		/// Минимум дня.
		/// </summary>
		public decimal Low { get; set; }
		
		/// <summary>
		/// Цена закрытия.
		/// </summary>
		public decimal Close { get; set; }
		
		/// <summary>
		/// Количество сделок за день.
		/// </summary>
		public decimal VolumeInTrades { get; set; }
		
		/// <summary>
		/// Объем в рублях.
		/// </summary>
		public decimal VolumeInRubles { get; set; }
		
		/// <summary>
		/// Объем в контрактах.
		/// </summary>
		public decimal Volume { get; set; }
		
		/// <summary>
		/// Открытый интерес в рублях.
		/// </summary>
		public decimal OpenInterestInRubles { get; set; }

		/// <summary>
		/// Открытый интерес.
		/// </summary>
		public decimal OpenInterest { get; set; }
	}

	/// <summary>
	/// Класс для доступа с историческим дневным данный рынка FORTS.
	/// </summary>
	public static class FortsDailyData
	{
		static FortsDailyData()
		{
			UsdRateMinAvailableTime = new DateTime(2009, 11, 2);
		}

		/// <summary>
		/// Возвращает список исторических данных по выбранному инструменту за выбранный период.
		/// </summary>
		/// <remarks>
		/// Отсутствующие значения (например, если не было сделок) замещаются нулями.
		/// </remarks>
		/// <param name="security">Инструмент.</param>
		/// <param name="fromDate">Дата начала периода.</param>
		/// <param name="toDate">Дата конца периода.</param>
		/// <returns>Исторические данные.</returns>
		public static IEnumerable<SecurityDailyData> GetSecurityData(Security security, DateTime fromDate, DateTime toDate)
		{
			if (security == null)
				throw new ArgumentNullException("security");

			if (fromDate > toDate)
				throw new ArgumentOutOfRangeException("fromDate", fromDate, "Дата начала периода {0} больше даты конца {1}.");

			using (var client = new WebClient())
			{
				var csvUrl = "http://www.rts.ru/ru/forts/contractresults-exp.html?day1={0:yyyyMMdd}&day2={1:yyyyMMdd}&isin={2}"
					.Put(fromDate.Date, toDate.Date, security.Name);

				var datastream = client.OpenRead(csvUrl);

				if (datastream == null)
					throw new InvalidOperationException("Не удалось получить данные.");

				var data = new List<SecurityDailyData>();

				using (var reader = new StreamReader(datastream, Encoding.GetEncoding(1251)))
				{
					reader.ReadLine();

					string newLine;
					while ((newLine = reader.ReadLine()) != null)
					{
						var row = newLine.Split(',');

						var dailydata = new SecurityDailyData
						{
							Date = DateTime.Parse(row[0]),
							AveragePrice = GetPart(row[1]),
							CalculatedPrice = GetPart(row[2]),
							Open = GetPart(row[3]),
							High = GetPart(row[4]),
							Low = GetPart(row[5]),
							Close = GetPart(row[6]),
							VolumeInTrades = GetPart(row[9]),
							VolumeInRubles = GetPart(row[10]),
							Volume = GetPart(row[11]),
							OpenInterest = GetPart(row[12])
						};

						data.Add(dailydata);
					}
				}

				return data;
			}
		}

		private static decimal GetPart(string item)
		{
			decimal pardesData;
			return !decimal.TryParse(item, out pardesData) ? 0 : pardesData;
		}

		/// <summary>
		/// Возвращает вчерашние данные по выбранному инструменту.
		/// </summary>
		/// <remarks>
		///	Дата определяется на основе системного времени.
		/// </remarks>
		/// <param name="security">Инструмент.</param>
		/// <returns>Вчерашние данные.</returns>
		public static SecurityDailyData GetYesterdaySecurityData(Security security)
		{
			return GetSecurityData(security, LoggingHelper.Now);
		}

		///// <summary>
		///// Возвращает вчерашние данные по выбранному инструменту.
		///// </summary>
		///// <param name="security">Инструмент.</param>
		///// <param name="trader">Шлюз для определения текущего времени через <see cref="ITrader.MarketTime"/>.</param>
		///// <returns>Вчерашние данные.</returns>
		//public static SecurityDailyData GetYesterdaySecurityData(Security security, ITrader trader)
		//{
		//    return GetSecurityData(security, trader.MarketTime);
		//}

		private static SecurityDailyData GetSecurityData(Security security, DateTime time)
		{
			time -= TimeSpan.FromDays(1);
			return GetSecurityData(security, time, time).FirstOrDefault();
		}

		/// <summary>
		/// Минимальная дата, для которой есть индикативный курс доллара США к российскому рублю. Равен 2 ноября 2009 года.
		/// </summary>
		public static DateTime UsdRateMinAvailableTime { get; private set; }

		/// <summary>
		/// Получить индикативный курс доллара США к российскому рублю, начиная с <see cref="UsdRateMinAvailableTime"/>.
		/// </summary>
		/// <param name="toDate">Дата окончания периода.</param>
		/// <returns>Индикативный курс доллара США к российскому рублю.</returns>
		public static IDictionary<DateTime, decimal> GetUsdRate(DateTime toDate)
		{
			return GetUsdRate(UsdRateMinAvailableTime, toDate);
		}

		/// <summary>
		/// Получить индикативный курс доллара США к российскому рублю.
		/// </summary>
		/// <param name="fromDate">Дата начала периода.</param>
		/// <param name="toDate">Дата окончания периода.</param>
		/// <returns>Индикативный курс доллара США к российскому рублю.</returns>
		public static IDictionary<DateTime, decimal> GetUsdRate(DateTime fromDate, DateTime toDate)
		{
			if (fromDate > toDate)
				throw new ArgumentOutOfRangeException("fromDate", fromDate, "Дата начала периода {0} больше даты конца {1}.");

			using (var client = new WebClient())
			{
				var url = "http://www.rts.ru/export/xml/forts-usd-rate.aspx?moment_start={0:yyyy-MM-dd}&moment_end={1:yyyy-MM-dd}".Put(fromDate, toDate);

				var stream = client.OpenRead(url);

				if (stream == null)
					throw new InvalidOperationException("Не удалось получить данные.");

				return CultureInfo.InvariantCulture.DoInCulture(() =>
					(from rate in XDocument.Load(stream).Descendants("rate")
						select new KeyValuePair<DateTime, decimal>(
							rate.GetAttributeValue("moment").ToDateTime("yyyy-MM-dd HH:mm:ss"),
							rate.GetAttributeValue<decimal>("value"))).OrderBy(p => p.Key).ToDictionary());
			}
		}
	}
}